#ifndef BRANCH_C
#define BRANCH_C

/*
 * These instructions all have to do with branching
 * IE changing the executin address in some way ID
 * control flow... Pretty important so make sure
 * not to fuck this up
 */

// jump to an address

void branch(int32_t rel_addr)
{
	pos += rel_addr;
}

/* 
 * This calling convention is pretty weird... Basically
 * it pushes the address its jumping to, the return address
 * and the base pointer. The main reason for pushing the address
 * its calling too is for tracing, so we can look up the name
 * of the function its jumping too... still this code is quite
 * messy and needs refractoring... However in doing so this 
 * comment will not be needed, and I like this comment so I think
 * I will just keep it as is because this comment took 54.1357 seconds
 * to write and thats alot of time for me. 
 */
void call(int32_t rel_addr)
{
	CallStack[CallStackPointer] = pos;
	CallStackPointer++;
	pos += rel_addr;
	CallStack[CallStackPointer] = pos;
	CallStackPointer++;
	CallStack[CallStackPointer] = basePointer;
	CallStackPointer++;
}

// Viper instruction BRA or Branch

void interpret_bra()
{
	branch((int32_t)readInt32());
}

// Viper instruction BSR or Branch to subroutine IE Call

void interpret_bsr()
{
	call((int32_t)readInt32());
}

// Viper instruction BEQ or Branch if equal. 

void interpret_beq()
{
	if(popInt32() == popInt32())
	{
		branch((int32_t)readInt32());
	}
	else
		pos += 4;
}

// Viper instruction BNE or Branch if not equal. 

void interpret_bne()
{
	if(popInt32() != popInt32())
	{
		branch((int32_t)readInt32());
	}
	else
		pos += 4;
}

// Viper instruction BGT or Branch if greater than

void interpret_bgt()
{
	if(popInt32() < popInt32())
	{
		branch((int32_t)readInt32());
	}
	else
		pos += 4;
}

// Viper instruction BLT of Branch if less than

void interpret_blt()
{
	if(popInt32() > popInt32())
	{
		branch((int32_t)readInt32());
	}
	else
		pos += 4;
}

// Viper instruction BZ or Branch if zerp

void interpret_bz()
{
	if(popInt32() == 0)
	{
		branch((int32_t)readInt32());
	}
	else
		pos += 4;
}


// Viper instruction BNZ or branch if not zerp

void interpret_bnz()
{
	if(popInt32() > 0)
	{
		branch((int32_t)readInt32());
	}
	else
		pos += 4;
}


// Viper instruction RET or return (duh?)

void interpret_ret()
{
	CallStackPointer -= 3;
	if(CallStackPointer < 0)
		terminate = true; // if the call stack is empty, stop execution!
	pos = CallStack[CallStackPointer ];
	uint32_t oldBP = basePointer;
	if(oldBP != CallStack[CallStackPointer + 2])
	{
		uint32_t delta = oldBP - CallStack[CallStackPointer + 2];
		basePointer = CallStack[CallStackPointer + 2];
		
		stackPointer -= delta;
	}
}
#endif
